Книги по языку программирования объясняют, что типы значений создаются в стеке, а ссылочные типы создаются в куче, без объяснения, что это за две вещи. Я не читал четкого объяснения этого. Я понимаю, что такое стек. Но, Где и что они (физически в памяти реального компьютера)? В какой степени они контролируются ОС или средой выполнения языка? Каков их объем? От чего зависит размер каждого из них? Что делает человека быстрее?
2020-12-07 21:43:48
Стек - это память, выделенная как временное пространство для потока выполнения. При вызове функции наверху стека резервируется блок для локальных переменных и некоторых данных бухгалтерского учета. Когда эта функция возвращается, блок становится неиспользуемым и может быть использован при следующем вызове функции. Стек всегда резервируется в порядке LIFO (последний пришел - первый ушел); самый последний зарезервированный блок всегда является следующим освобождаемым блоком. Это упрощает отслеживание стека; освобождение блока из стека - это не что иное, как настройка одного указателя. Куча - это память, отведенная для динамического распределения. В отличие от стека, здесь нет принудительного шаблона для выделения и освобождения блоков из кучи; вы можете выделить блок в любое время и освободить его в любое время. Это значительно усложняет отслеживание того, какие части кучи выделены или освобождены в любой момент времени; доступно множество настраиваемых распределителей кучи для настройки производительности кучи для различных схем использования. Каждый поток получает стек, в то время как обычно существует только одна куча для приложения (хотя нередко бывает несколько куч для разных типов распределения). Чтобы напрямую ответить на ваши вопросы: В какой степени они контролируются ОС или языковой средой? ОС выделяет стек для каждого потока системного уровня при создании потока. Обычно ОС вызывается средой выполнения языка для выделения кучи для приложения. Каков их объем? Стек прикреплен к потоку, поэтому, когда поток выходит из стека, он восстанавливается. Куча обычно выделяется при запуске приложения средой выполнения и освобождается при выходе из приложения (технически процесса). От чего зависит размер каждого из них? Размер стека устанавливается при создании потока. Размер кучи устанавливается при запуске приложения, но может увеличиваться по мере необходимости в пространстве (распределитель запрашивает у операционной системы больше памяти). Что делает человека быстрее? Стек работает быстрее, потому что шаблон доступа упрощает выделение и освобождение памяти из него (указатель / целое число просто увеличивается или уменьшается), в то время как в куче гораздо более сложный учет, связанный с выделением или освобождением. Кроме того, каждый байт в стеке имеет тенденцию очень часто повторно использоваться, что означает, что он имеет тенденцию отображаться в кэш процессора, что делает его очень быстрым. Еще одним ударом по производительности кучи является то, что куча, являющаяся в основном глобальным ресурсом, обычно должна быть многопоточной, то есть каждое выделение и освобождение должно - обычно - синхронизироваться со «всеми» другими доступами к куче в программе. Наглядная демонстрация: Источник изображения: vikashazrati.wordpress.com | Стек: Хранится в оперативной памяти компьютера как в куче. Переменные, созданные в стеке, выходят из области видимости и автоматически освобождаются. Гораздо быстрее выделять по сравнению с переменными в куче. Реализован с реальной структурой данных стека. Хранит локальные данные, адреса возврата, используемые для передачи параметров. Может иметь место переполнение стека, когда используется слишком большая часть стека (в основном из-за бесконечной или слишком глубокой рекурсии, очень больших выделений). Данные, созданные в стеке, можно использовать без указателей. Вы бы использовали стек, если точно знаете, сколько данных вам нужно выделить до времени компиляции, и он не слишком большой. Обычно максимальный размер уже определяется при запуске вашей программы. Куча: Хранится в оперативной памяти компьютера как в стеке. В C ++ переменные в куче должны быть уничтожены вручную и никогда не выпадают из области видимости. Данные освобождаются с помощью delete, delete [] или free. Медленнее выделяется по сравнению с переменными в стеке. Используется по запросу для выделения блока данных для использования программой. Может иметь место фрагментация при большом количестве распределений и освобождений. В C ++ или C данные, созданные в куче, будут указываться указателями и выделены с помощью new или malloc соответственно. Могут происходить сбои выделения, если требуется выделить слишком большой буфер. Вы бы использовали кучу, если не знаете точно, сколько данных вам понадобится во время выполнения или если вам нужно выделить много данных. Ответственный за утечки памяти. Пример: int foo () { char * pBuffer; // <- еще ничего не выделено (за исключением самого указателя, который размещен здесь, в стеке). bool b = true; // Выделено в стеке. если (б) { // Создаем 500 байт в стеке char buffer [500]; // Создаем 500 байт в куче pBuffer = новый символ [500]; } // <- буфер здесь освобожден, pBuffer - нет } // <--- ой, утечка памяти, мне следовало вызвать delete [] pBuffer; | Наиболее важным моментом является то, что куча и стек - это общие термины для способов выделения памяти. Они могут быть реализованы разными способами, и эти термины относятся к основным концепциям. В стопке элементов элементы располагаются друг над другом в том порядке, в котором они были размещены, и вы можете удалить только верхний(не опрокидывая все это). Простота стека заключается в том, что вам не нужно поддерживать таблицу, содержащую запись каждого раздела выделенной памяти; единственная информация о состоянии, которая вам нужна, - это единственный указатель на конец стека. Чтобы выделить и освободить, вы просто увеличиваете и уменьшаете этот единственный указатель. Примечание: иногда стек можно реализовать так, чтобы он начинался с вершины раздела памяти и продолжался вниз, а не вверх. В куче нет определенного порядка размещения элементов. Вы можете достать и удалить элементы в любом порядке, потому что нет четкого «верхнего» элемента. Выделение кучи требует ведения полной записи о том, какая память выделена, а какая нет, а также некоторых накладных расходов для уменьшения фрагментации, поиска смежных сегментов памяти, достаточно больших, чтобы соответствовать запрошенному размеру, и так далее. Память можно освободить в любой момент, оставив свободное место. Иногда распределитель памяти выполняет задачи обслуживания, такие как дефрагментация памяти путем перемещения выделенной памяти или сбор мусора - определение во время выполнения, когда память больше не находится в области видимости и освобождение ее. Эти изображения должны достаточно хорошо описывать два способа выделения и освобождения памяти в стеке и куче. Ням! В какой степени они контролируются ОС или языковой средой? Как уже упоминалось, «куча» и «стек» - это общие термины, которые можно реализовать разными способами. Компьютерные программы обычно имеют стек, называемый стеком вызовов, в котором хранится информация, относящаяся к текущей функции, например указатель на ту функцию, из которой она была вызвана, и любые локальные переменные. Поскольку функции вызывают другие функции, а затем возвращаются, стек увеличивается и сжимается, чтобы хранить информацию от функций, находящихся ниже по стеку вызовов. Программа фактически не контролирует ее во время выполнения; это определяется языком программирования, ОС и даже архитектурой системы. Куча - это общий термин, используемый для любой памяти, которая выделяется динамически и случайным образом; т.е. вышло из строя. Память обычно выделяется ОС, а приложение вызывает функции API для этого выделения. При управлении динамически выделяемой памятью требуются значительные накладные расходы, которые обычно обрабатываются кодом времени выполнения используемого языка программирования или среды. Каков их объем? Стек вызовов - это настолько низкоуровневая концепция, что она не имеет отношения к «области действия» в смысле программирования. Если вы дизассемблируете какой-то код, вы увидите относительные ссылки стиля указателя на части стека, но, что касается языка более высокого уровня, язык накладывает свои собственные правила области видимости. Однако одним из важных аспектов стека является то, что после возврата из функции все, что является локальным для этой функции, немедленно освобождается из стека. Это работает так, как вы ожидаете, учитывая то, как работают ваши языки программирования. В куче тоже сложно определить. Область видимости - это все, что предоставляется ОС, но ваш язык программирования, вероятно, добавляет свои правила о том, что такое «область видимости» в вашем приложении. Архитектура процессора и ОС используют виртуальную адресацию, которую процессор преобразует в физические адреса, при этом возникают ошибки страниц и т. Д. Они отслеживают, какие страницы каким приложениям принадлежат. Однако вам никогда не стоит об этом беспокоиться, потому что вы просто используете любой метод, который использует ваш язык программирования для выделения и освобождения памяти и проверки на наличие ошибок (если распределение / освобождение не удается по какой-либо причине). От чего зависит размер каждого из них? Опять же, это зависит от языка, компилятора, операционной системы и архитектуры. Стек обычно выделяется заранее, потому что по определению это должна быть непрерывная память. Компилятор языка или ОС определяют его размер. Вы не храните огромные фрагменты данных в стеке, поэтому он будет достаточно большим, чтобы его никогда нельзя было использовать полностью, за исключением случаев нежелательной бесконечной рекурсии (отсюда «переполнение стека») или других необычных программных решений. Куча - это общий термин для всего, что может быть размещено динамически. В зависимости от того, как вы на это смотрите, он постоянно меняет размер. В современных процессорах и операционных системах точный способ его работы в любом случае очень абстрагирован, поэтому вам обычно не нужно сильно беспокоиться о том, как он работает глубоко внутри, за исключением того, что (на языках, где это позволяет) вы не должны использовать память, которая вы еще не выделили или освободили память. Что делает человека быстрее? Стек работает быстрее, потому что вся свободная память всегда непрерывна. Нет необходимости вести список всех сегментов свободной памяти, только один указатель на текущую вершину стека. Для этой цели компиляторы обычно хранят этот указатель в специальном быстром регистре. Более того, последующие операции в стеке обычно сосредоточены в очень близких областях памяти, что на очень низком уровне хорошо для оптимизации процессором на кристалле.тайники. | (Я переместил этот ответ из другого вопроса, который был более или менее дублирован этим.) Ответ на ваш вопрос зависит от реализации и может различаться в зависимости от компилятора и архитектуры процессора. Однако вот упрощенное объяснение. И стек, и куча - это области памяти, выделенные из базовой операционной системы (часто виртуальная память, которая отображается на физическую память по запросу). В многопоточной среде каждый поток будет иметь свой собственный полностью независимый стек, но они будут совместно использовать кучу. Одновременный доступ должен контролироваться в куче и невозможен в стеке. Куча Куча содержит связанный список используемых и свободных блоков. Новые выделения в куче (с помощью new или malloc) удовлетворяются путем создания подходящего блока из одного из свободных блоков. Это требует обновления списка блоков в куче. Эта метаинформация о блоках в куче также хранится в куче, часто в небольшой области прямо перед каждым блоком. По мере роста кучи новые блоки часто распределяются с более низких адресов на более высокие. Таким образом, вы можете думать о куче как о куче блоков памяти, размер которой увеличивается по мере выделения памяти. Если куча слишком мала для выделения, размер часто можно увеличить, получив больше памяти из базовой операционной системы. Выделение и освобождение большого количества небольших блоков может привести к тому, что куча останется в состоянии, когда между используемыми блоками будет перемежаться много маленьких свободных блоков. Запрос на выделение большого блока может завершиться неудачно, потому что ни один из свободных блоков не является достаточно большим, чтобы удовлетворить запрос на выделение, даже если объединенный размер свободных блоков может быть достаточно большим. Это называется фрагментацией кучи. Когда используемый блок, который находится рядом со свободным блоком, освобождается, новый свободный блок может быть объединен со смежным свободным блоком, чтобы создать свободный блок большего размера, эффективно уменьшая фрагментацию кучи. Стек Стек часто работает в тесном тандеме со специальным регистром ЦП, называемым указателем стека. Изначально указатель стека указывает на вершину стека (самый высокий адрес в стеке). ЦП имеет специальные инструкции для помещения значений в стек и извлечения их обратно из стека. Каждое нажатие сохраняет значение в текущем местоположении указателя стека и уменьшает указатель стека. Pop извлекает значение, на которое указывает указатель стека, а затем увеличивает указатель стека (вас не смущает тот факт, что добавление значения в стек уменьшает указатель стека, а удаление значения увеличивает его. Помните, что стек увеличивается до дно). Сохраненные и извлеченные значения - это значения регистров ЦП. Когда функция вызывается, ЦП использует специальные инструкции, которые перемещают указатель текущей инструкции, то есть адрес кода, выполняемого в стеке. Затем ЦП переходит к функции, устанавливая указатель инструкции на адрес вызываемой функции. Позже, когда функция возвращается, старый указатель инструкции извлекается из стека, и выполнение возобновляется с кода сразу после вызова функции. Когда функция вводится, указатель стека уменьшается, чтобы выделить больше места в стеке для локальных (автоматических) переменных. Если функция имеет одну локальную 32-битную переменную, в стеке выделяются четыре байта. Когда функция возвращается, указатель стека перемещается назад, чтобы освободить выделенную область. Если функция имеет параметры, они помещаются в стек перед вызовом функции. Затем код функции может перемещаться вверх по стеку от текущего указателя стека, чтобы найти эти значения. Вызовы вложенных функций работают как шарм. Каждый новый вызов будет выделять параметры функции, адрес возврата и пространство для локальных переменных, и эти записи активации могут быть сложены для вложенных вызовов и будут правильно раскручиваться, когда функции вернутся. Поскольку стек представляет собой ограниченный блок памяти, вы можете вызвать переполнение стека, вызвав слишком много вложенных функций и / или выделив слишком много места для локальных переменных. Часто область памяти, используемая для стека, настраивается таким образом, что запись ниже нижнего (самого нижнего адреса) стека вызывает прерывание или исключение в ЦП. Это исключительное состояние затем может быть обнаружено средой выполнения и преобразовано в какое-то исключение переполнения стека. Можно ли разместить функцию в куче вместо стека? Нет, записи активации для функций (то есть локальных или автоматических переменных) размещаются в стеке, который используется не только для хранения этих переменных, но и для отслеживания вызовов вложенных функций. Как управлять кучей, действительно зависит от среды выполнения. C использует malloc, а C ++ использует new, но во многих других языках есть сборка мусора. Однако стек - это функция более низкого уровня, тесно связанная с архитектурой процессора. Вырастить кучу, когда недостаточно места, не так уж сложно, так какэто может быть реализовано в вызове библиотеки, которая обрабатывает кучу. Однако увеличение стека часто невозможно, так как переполнение стека обнаруживается только тогда, когда уже слишком поздно; и отключение потока выполнения - единственный жизнеспособный вариант. | В следующем коде C # public void Method1 () { int я = 4; int y = 2; class1 cls1 = новый class1 (); } Вот как управляется память Локальные переменные, которые должны существовать только до тех пор, пока вызов функции находится в стеке. Куча используется для переменных, время жизни которых мы не знаем заранее, но мы ожидаем, что они продлятся некоторое время. Для большинства языков очень важно знать во время компиляции, насколько велика переменная, если мы хотим сохранить ее в стеке. Объекты (которые меняются по размеру по мере их обновления) отправляются в кучу, потому что во время создания мы не знаем, как долго они прослужат. Во многих языках куча собирается сборщиком мусора для поиска объектов (таких как объект cls1), на которые больше нет ссылок. В Java большинство объектов попадают прямо в кучу. В таких языках, как C / C ++, структуры и классы часто могут оставаться в стеке, когда вы не имеете дело с указателями. Более подробную информацию можно найти здесь: Разница между выделением памяти в стеке и куче «timmurphy.org и здесь: Создание объектов в стеке и куче Эта статья является источником изображения выше: Шесть важных концепций .NET: стек, куча, типы значений, ссылочные типы, упаковка и распаковка - CodeProject но имейте в виду, что он может содержать некоторые неточности. | Стек Когда вы вызываете функцию, аргументы этой функции плюс некоторые другие накладные расходы помещаются в стек. Некоторая информация (например, куда пойти по возвращении) также хранится там. Когда вы объявляете переменную внутри своей функции, эта переменная также выделяется в стеке. Освободить стек довольно просто, потому что вы всегда освобождаете в обратном порядке. Стек добавляется при вводе функций, соответствующие данные удаляются при выходе из них. Это означает, что вы склонны оставаться в пределах небольшой области стека, если вы не вызываете множество функций, которые вызывают множество других функций (или не создаете рекурсивное решение). Куча Куча - это общее имя, в которое вы помещаете данные, которые вы создаете на лету. Если вы не знаете, сколько космических кораблей собирается создать ваша программа, вы, вероятно, воспользуетесь оператором new (или malloc или эквивалентным) для создания каждого космического корабля. Это распределение будет сохраняться какое-то время, поэтому вполне вероятно, что мы освободим вещи в другом порядке, чем мы их создали. Таким образом, куча намного сложнее, потому что в конечном итоге остаются неиспользуемые области памяти, чередующиеся с фрагментами, которые - память фрагментируется. Найти свободную память нужного размера - сложная задача. Вот почему следует избегать кучи (хотя она все еще часто используется). Реализация Реализация как стека, так и кучи обычно зависит от среды выполнения / ОС. Часто игры и другие приложения, критичные к производительности, создают свои собственные решения для памяти, которые захватывают большой кусок памяти из кучи и затем распределяют его внутри, чтобы не полагаться на ОС в качестве памяти. Это практично только в том случае, если ваше использование памяти сильно отличается от нормы - то есть для игр, где вы загружаете уровень за одну огромную операцию и можете выбросить все это за другую огромную операцию. Физическое расположение в памяти Это менее актуально, чем вы думаете, из-за технологии, называемой виртуальной памятью, которая заставляет вашу программу думать, что у вас есть доступ к определенному адресу, где физические данные находятся где-то еще (даже на жестком диске!). Адреса, которые вы получаете для стека, располагаются в порядке возрастания по мере того, как ваше дерево вызовов становится глубже. Адреса кучи непредсказуемы (т.е. зависят от имплементации) и, откровенно говоря, не важны. | Чтобы уточнить, в этом ответе неверная информация (Томас исправил свой ответ после комментариев, круто :)). В других ответах просто не объясняется, что означает статическое распределение. Итак, я объясню три основных формы распределения и то, как они обычно связаны с кучей, стеком и сегментом данных ниже. Я также покажу несколько примеров как на C / C ++, так и на Python, чтобы помочь людям понять. «Статические» (также известные как статически размещенные) переменные не размещаются в стеке. Не думайте об этом - многие люди так делают только потому, что «статика» очень похожа на «стек». На самом деле они не существуют ни в стеке, ни в куче. Это часть того, что называется сегментом данных. Однако, как правило, лучше рассматривать «область действия» и «время жизни», чем «стек» и «кучу». Область действия означает, какие части кода могут обращаться к переменной. Обычно мы думаем о локальной области видимости (доступ к которой может получить только текущая функция) и глобальной области (доступ к ней возможен где угодно), хотя область видимости может стать намного более сложной. Время жизни означает, когда переменная выделяется и освобождается во время выполнения программы. Обычно мы думаем о статическом распределении (переменнаябудет сохраняться на протяжении всей программы, что делает его полезным для хранения одной и той же информации для нескольких вызовов функций) по сравнению с автоматическим распределением (переменная сохраняется только во время одного вызова функции, что делает ее полезной для хранения информации, которая используется только во время вашего функция и может быть отброшена, как только вы закончите) по сравнению с динамическим распределением (переменные, продолжительность которых определяется во время выполнения, а не во время компиляции, например статическое или автоматическое). Хотя большинство компиляторов и интерпретаторов реализуют это поведение аналогичным образом с точки зрения использования стеков, куч и т. Д., Компилятор может иногда нарушать эти соглашения, если он хочет, если поведение является правильным. Например, из-за оптимизации локальная переменная может существовать только в регистре или быть полностью удалена, даже если большинство локальных переменных существует в стеке. Как было указано в нескольких комментариях, вы можете реализовать компилятор, который даже не использует стек или кучу, а вместо этого использует некоторые другие механизмы хранения (редко, поскольку стеки и кучи отлично подходят для этого). Я предоставлю простой аннотированный код на C, чтобы проиллюстрировать все это. Лучший способ научиться - запустить программу под отладчиком и наблюдать за ее поведением. Если вы предпочитаете читать Python, переходите к концу ответа :) // Статически размещается в сегменте данных при первой загрузке программы / DLL // Освобождается при выходе из программы / DLL // область видимости - можно получить доступ из любой точки кода int someGlobalVariable; // Статически размещается в сегменте данных при первой загрузке программы // Освобождается при выходе из программы / DLL // область - можно получить доступ из любого места в этом конкретном файле кода статический int someStaticVariable; // "someArgument" выделяется в стеке каждый раз, когда вызывается MyFunction // "someArgument" освобождается, когда MyFunction возвращает // область видимости - доступна только в MyFunction () void MyFunction (int someArgument) { // Статически размещается в сегменте данных при первой загрузке программы // Освобождается при выходе из программы / DLL // область видимости - доступна только в MyFunction () статический int someLocalStaticVariable; // Выделяется в стеке при каждом вызове MyFunction // Освобождается, когда MyFunction возвращает // область видимости - доступна только в MyFunction () int someLocalVariable; // * указатель * выделяется в стеке каждый раз, когда вызывается MyFunction // Этот указатель освобождается, когда MyFunction возвращает // область видимости - к указателю можно получить доступ только внутри MyFunction () int * someDynamicVariable; // Эта строка вызывает выделение места для целого числа в куче // когда эта строка выполняется. Обратите внимание, это не в начале // вызов MyFunction (), как автоматические переменные // область видимости - только код внутри MyFunction () может получить доступ к этому пространству // * через эту конкретную переменную *. // Однако, если вы передадите адрес в другое место, этот код // тоже можем получить к нему доступ someDynamicVariable = новый интервал; // Эта строка освобождает место для целого числа в куче. // Если бы мы его не записывали, память была бы «просочена». // Обратите внимание на фундаментальную разницу между стеком и кучей // кучей нужно управлять. Стек управляется за нас. удалить someDynamicVariable; // В других случаях вместо освобождения этого пространства кучи вы // может сохранить адрес в более постоянном месте, чтобы использовать его позже. // Некоторые языки даже позаботятся об освобождении памяти за вас ... но // всегда о нем нужно позаботиться во время выполнения каким-либо механизмом. // Когда функция возвращается, someArgument, someLocalVariable // и указатель someDynamicVariable освобождаются. // Пробел, на который указывает someDynamicVariable, уже был // освобождается перед возвратом. возвращение; } // Обратите внимание, что someGlobalVariable, someStaticVariable и // someLocalStaticVariable продолжает существовать, но не // освобождается до выхода из программы. Особенно ярким примером того, почему важно различать время жизни и область видимости, является то, что переменная может иметь локальную область видимости, но статическое время жизни - например, someLocalStaticVariable в приведенном выше примере кода. Такие переменные могут очень запутать наши обычные, но неформальные привычки именования. Например, когда мы говорим «локальный», мы обычно имеем в виду «автоматически выделяемую переменную с локальным охватом», а когда мы говорим «глобальный», мы обычно имеем в виду «статически выделенную переменную с глобальным охватом». К сожалению, когда дело доходит до таких вещей, как «статически распределенные переменные в области видимости файла», многие люди просто говорят… «да ???». Некоторые варианты синтаксиса C / C ++ усугубляют эту проблему - например, многие люди думают, что глобальные переменные не «статичны» из-за синтаксиса, показанного ниже. int var1; // Имеет глобальную область видимости и статическое размещение статический int var2; // Имеет область видимости файла и статическое размещение int main () {return 0;} Обратите внимание, что размещение ключевого слова static в объявлении выше предотвращает глобальную область видимости var2. Тем не менее, глобальная переменная var1 имеет статическое размещение. Это неинтуитивно понятный! По этой причине я стараюсь никогда не использовать слово «статический» при описании области видимости, а вместо этого говорю что-то вроде «область видимости файла» или «ограниченная файлом». Однако многие люди используют фразу «статическая» или «статическая область видимости» для описания переменной, к которой можно получить доступ только из одного файла кода. В контексте времени жизни «статический» всегда означает, что переменная выделяется при запуске программы и освобождается при выходе из программы. Некоторые люди считают эти концепции специфичными для C / C ++. Они не. Например, приведенный ниже пример Python иллюстрирует все три типа распределения (в интерпретируемых языках возможны некоторые тонкие различия, которые я здесь не буду описывать). from datetime import datetime класс Animal: _FavoriteFood = 'Undefined' # _FavoriteFood размещается статически def PetAnimal (сам): curTime = datetime.time (datetime.now ()) # curTime выделяется автоматически print («Спасибо, что погладили меня. Но это« + str (curTime) + », ты должен меня покормить. Моя любимая еда -« + self._FavoriteFood ») класс Cat (Животное): _FavoriteFood = 'tuna' # Обратите внимание, поскольку мы переопределяем, класс Cat имеет свою собственную статически выделенную переменную _FavoriteFood, отличную от переменной Animal класс Dog (Животное): _FavoriteFood = 'steak' # Точно так же класс Dog получает собственную статическую переменную. Важно отметить - эта статическая переменная используется всеми экземплярами Dog, поэтому она не является динамической! если __name__ == "__main__": whiskers = Cat () # Распределяется динамически fido = Dog () # Распределяется динамически rinTinTin = Dog () # Распределяется динамически усы.PetAnimal () fido.PetAnimal () rinTinTin.PetAnimal () Dog._FavoriteFood = 'молочные кости' усы.PetAnimal () fido.PetAnimal () rinTinTin.PetAnimal () # Вывод: # Спасибо, что погладили меня. Но сейчас 13: 05: 02.255000, ты должен меня покормить. Моя любимая еда - тунец # Спасибо, что погладили меня. Но сейчас 13: 05: 02.255000, ты должен меня покормить. Моя любимая еда - стейк # Спасибо, что погладили меня. Но сейчас 13: 05: 02.255000, ты должен меня покормить. Моя любимая еда - стейк # Спасибо, что погладили меня. Но сейчас 13: 05: 02.255000, ты должен меня покормить. Моя любимая еда - тунец # Спасибо, что погладили меня. Но сейчас 13: 05: 02.255000, ты должен меня покормить. Моя любимая еда - молочные кости # Спасибо, что погладили меня. Но сейчас 13: 05: 02.256000, ты должен меня покормить. Моя любимая еда - молочные кости | Другие довольно хорошо ответили на общие черты, поэтому я добавлю несколько деталей. Стек и куча не обязательно должны быть единичными. Распространенная ситуация, когда у вас есть более одного стека, - это если у вас есть более одного потока в процессе. В этом случае у каждого потока есть свой стек. У вас также может быть более одной кучи, например, некоторые конфигурации DLL могут приводить к тому, что разные библиотеки DLL выделяются из разных куч, поэтому обычно плохая идея освобождать память, выделенную другой библиотекой. В C вы можете получить преимущество выделения переменной длины за счет использования alloca, которая выделяет в стеке, в отличие от alloc, которая выделяется в куче. Эта память не выдержит вашего оператора return, но она полезна для временного буфера. Создание огромного временного буфера в Windows, который вы мало используете, не является бесплатным. Это связано с тем, что компилятор будет генерировать цикл проверки стека, который вызывается каждый раз при входе в вашу функцию, чтобы убедиться, что стек существует (поскольку Windows использует одну защитную страницу в конце вашего стека, чтобы определить, когда ей нужно увеличить стек. Если вы обращаетесь к памяти более чем на одну страницу с конца стека, произойдет сбой). Пример: аннулировать мою функцию () { char big [10000000]; // Делаем то, что используется только для первых 1 КБ из больших 99% времени. } | Другие прямо ответили на ваш вопрос, но, пытаясь понять стек и кучу, я думаю, что полезно рассмотреть структуру памяти традиционного процесса UNIX (без потоков и распределителей на основе mmap ()). На веб-странице Глоссария управления памятью есть диаграмма этой структуры памяти. Стек и куча традиционно расположены на противоположных концах виртуального адресного пространства процесса. Стек автоматически увеличивается при доступе до размера, установленного ядром (который можно настроить с помощью setrlimit (RLIMIT_STACK, ...)). Куча увеличивается, когда распределитель памяти вызывает системный вызов brk () или sbrk (), отображая больше страниц физической памяти в виртуальное адресное пространство процесса. В системах без виртуальной памяти, таких как некоторые встроенные системы, часто применяется одна и та же базовая схема, за исключением того, что размер стека и кучи фиксирован. Однако в других встроенных системах (например, на основе микроконтроллеров Microchip PIC) программный стек представляет собой отдельный блок памяти, который не адресуется инструкциями перемещения данных и может быть изменен или прочитан только косвенно через инструкции потока программы (вызов, возврат и т. д.). Другие архитектуры, такие как процессоры Intel Itanium, имеют несколько стеков. В этом смысле стек является элементом архитектуры ЦП. | Стек - это частьпамяти, которой можно управлять с помощью нескольких ключевых инструкций на языке ассемблера, таких как pop (удалить и вернуть значение из стека) и push (отправить значение в стек), но также вызвать (вызвать подпрограмму - это подталкивает адрес для возврата в стек) и return (возврат из подпрограммы - это выталкивает адрес из стека и переходит к нему). Это область памяти ниже регистра указателя стека, которую можно настроить по мере необходимости. Стек также используется для передачи аргументов подпрограммам, а также для сохранения значений в регистрах перед вызовом подпрограмм. Куча - это часть памяти, которая предоставляется приложению операционной системой, как правило, посредством системного вызова, такого как malloc. В современных операционных системах эта память представляет собой набор страниц, к которым имеет доступ только вызывающий процесс. Размер стека определяется во время выполнения и обычно не увеличивается после запуска программы. В программе на C стек должен быть достаточно большим, чтобы вместить каждую переменную, объявленную в каждой функции. Куча будет расти динамически по мере необходимости, но ОС в конечном итоге выполняет вызов (она часто увеличивает кучу больше, чем значение, запрошенное malloc, так что по крайней мере некоторым будущим маллокам не нужно будет возвращаться в ядро получить больше памяти. Это поведение часто настраивается) Поскольку вы выделили стек перед запуском программы, вам никогда не нужно выполнять malloc, прежде чем вы сможете использовать стек, так что это небольшое преимущество. На практике очень сложно предсказать, что будет быстрым, а что медленным в современных операционных системах, имеющих подсистемы виртуальной памяти, потому что то, как реализованы страницы и где они хранятся, является деталью реализации. | Что такое стек? Стопка - это куча предметов, обычно аккуратно уложенных. Стеки в вычислительных архитектурах - это области памяти, в которые данные добавляются или удаляются в порядке очереди. В многопоточном приложении у каждого потока будет свой стек. Что такое куча? Куча - это неопрятное собрание вещей, скопившихся наугад. В вычислительных архитектурах куча - это область динамически выделяемой памяти, которая автоматически управляется операционной системой или библиотекой диспетчера памяти. Память в куче регулярно выделяется, освобождается и меняет размер во время выполнения программы, и это может привести к проблеме, называемой фрагментацией. Фрагментация происходит, когда объекты памяти выделяются с небольшими промежутками между ними, которые слишком малы для хранения дополнительных объектов памяти. Конечный результат - это процентная доля пространства кучи, которая не может использоваться для дальнейшего выделения памяти. Оба вместе В многопоточном приложении у каждого потока будет свой стек. Но все разные потоки будут совместно использовать кучу. Поскольку разные потоки совместно используют кучу в многопоточном приложении, это также означает, что между потоками должна быть некоторая координация, чтобы они не пытались получить доступ и манипулировать одним и тем же фрагментом (-ами) памяти в куче в в то же время. Что быстрее - стек или куча? И почему? Стек намного быстрее, чем куча. Это связано с тем, как память распределяется в стеке. Выделить память в стеке так же просто, как переместить указатель стека вверх. Для новичков в программировании, вероятно, будет хорошей идеей использовать стек, поскольку это проще. Поскольку стек небольшой, вы можете использовать его, когда точно знаете, сколько памяти вам понадобится для ваших данных, или если вы знаете, что размер ваших данных очень мал. Лучше использовать кучу, когда вы знаете, что вам понадобится много памяти для ваших данных, или вы просто не уверены, сколько памяти вам понадобится (например, с динамическим массивом). Модель памяти Java Стек - это область памяти, в которой хранятся локальные переменные (включая параметры метода). Когда дело доходит до объектных переменных, это просто ссылки (указатели) на фактические объекты в куче. Каждый раз, когда создается экземпляр объекта, часть памяти кучи выделяется для хранения данных (состояния) этого объекта. Поскольку объекты могут содержать другие объекты, некоторые из этих данных могут фактически содержать ссылки на эти вложенные объекты. | Я думаю, что многие другие люди дали вам в основном правильные ответы по этому поводу. Однако упущена одна деталь: "кучу" на самом деле следует называть "бесплатным хранилищем". Причина этого различия заключается в том, что исходное бесплатное хранилище было реализовано со структурой данных, известной как «биномиальная куча». По этой причине распределение из ранних реализаций malloc () / free () было распределением из кучи. Однако в наши дни большинство бесплатных хранилищ реализованы с очень сложными структурами данных, которые не являются биномиальными кучами. | Со стеком можно делать интересные вещи. Например, у вас есть такие функции, как alloca (при условии, что вы можете обойти многочисленные предупреждения относительно ее использования), которая является формой malloc, котораяспециально для памяти использует стек, а не кучу. Тем не менее, стековые ошибки памяти - одни из худших, с которыми я сталкивался. Если вы используете память кучи и вы выходите за пределы выделенного блока, у вас есть приличный шанс вызвать ошибку сегмента. (Не на 100%: ваш блок может случайно быть смежным с другим, который вы ранее разместили.) Но поскольку переменные, созданные в стеке, всегда смежны друг с другом, запись за пределы может изменить значение другой переменной. Я понял, что всякий раз, когда я чувствую, что моя программа перестала подчиняться законам логики, это, вероятно, переполнение буфера. | Проще говоря, стек - это место, где создаются локальные переменные. Кроме того, каждый раз, когда вы вызываете подпрограмму, счетчик программы (указатель на следующую машинную инструкцию) и любые важные регистры, а иногда и параметры помещаются в стек. Затем любые локальные переменные внутри подпрограммы помещаются в стек (и используются оттуда). Когда подпрограмма завершается, весь этот материал удаляется обратно из стека. Данные ПК и регистра возвращаются и возвращаются на прежнее место, так что ваша программа может продолжать свой жизненный путь. Куча - это область памяти, из которой выполняется распределение динамической памяти (явные вызовы «new» или «allocate»). Это особая структура данных, которая может отслеживать блоки памяти различного размера и их статус распределения. В «классических» системах ОЗУ располагалась так, что указатель стека начинался снизу памяти, указатель кучи начинался сверху, и они увеличивались по направлению друг к другу. Если они перекрываются, у вас закончилась оперативная память. Однако это не работает с современными многопоточными ОС. У каждого потока должен быть свой стек, и они могут создаваться динамически. | Из WikiAnwser. Стек Когда функция или метод вызывает другую функцию, которая по очереди вызывает другую функцию и т. Д., Выполнение всех этих функций остается приостановленным до тех пор, пока самая последняя функция не вернет свое значение. Эта цепочка приостановленных вызовов функций является стеком, потому что элементы в стеке (вызовы функций) зависят друг от друга. Стек важно учитывать при обработке исключений и выполнении потоков. Куча Куча - это просто память, используемая программами для хранения переменных. Элементы кучи (переменные) не зависят друг от друга и всегда могут быть доступны случайным образом в любое время. | Стек Очень быстрый доступ Не нужно явно освобождать переменные Пространство эффективно управляется процессором, память не будет фрагментирована Только локальные переменные Ограничение на размер стека (зависит от ОС) Размер переменных нельзя изменить Куча Доступ к переменным возможен глобально Нет ограничений на размер памяти (Относительно) более медленный доступ Нет гарантированного эффективного использования пространства, память со временем может фрагментироваться, поскольку блоки памяти выделяются, а затем освобождаются Вы должны управлять памятью (вы отвечаете за выделение и освобождение переменных) Размер переменных можно изменять с помощью realloc () | Короче говоря Стек используется для распределения статической памяти, а куча - для распределения динамической памяти, которые хранятся в оперативной памяти компьютера. В деталях Стек Стек представляет собой структуру данных «LIFO» (последний пришел - первым ушел), которая довольно тщательно управляется и оптимизируется процессором. Каждый раз, когда функция объявляет новую переменную, она «помещается» в стек. Затем каждый раз, когда функция завершается, все переменные, помещенные этой функцией в стек, освобождаются (то есть они удаляются). После освобождения переменной стека эта область памяти становится доступной для других переменных стека. Преимущество использования стека для хранения переменных состоит в том, что память управляется за вас. Вам не нужно выделять память вручную или освобождать ее, если она вам больше не нужна. Более того, поскольку ЦП так эффективно организует стековую память, чтение и запись переменных стека происходит очень быстро. Больше можно найти здесь. Куча Куча - это область памяти вашего компьютера, которая не управляется автоматически и не так жестко управляется ЦП. Это более свободно плавающая область памяти (и больше). Чтобы выделить память в куче, вы должны использовать malloc () или calloc (), которые являются встроенными функциями C. После того, как вы выделили память в куче, вы должны использовать free () для освобождения этой памяти, если она вам больше не нужна. Если вы этого не сделаете, ваша программа будет иметь так называемую утечку памяти. То есть память в куче по-прежнему будет выделена (и не будет доступна другим процессам). Как мы увидим в разделе отладки, есть инструмент Valgrind, который может помочь вам обнаружить утечки памяти. В отличие от стека, куча не имеет ограничений размера на переменный размер (кроме очевидных физических ограничений вашего компьютера). Память кучи немного медленнее для чтения и записи, потому что для доступа к памяти в куче необходимо использовать указатели. Мы скоро поговорим об указателях. В отличие от стека,переменные, созданные в куче, доступны любой функции в любом месте вашей программы. Переменные кучи по сути глобальны по своему охвату. Больше можно найти здесь. Переменные, размещенные в стеке, хранятся непосредственно в памяти, и доступ к этой памяти осуществляется очень быстро, и ее выделение выполняется при компиляции программы. Когда функция или метод вызывает другую функцию, которая по очереди вызывает другую функцию и т. Д., Выполнение всех этих функций остается приостановленным до тех пор, пока самая последняя функция не вернет свое значение. Стек всегда резервируется в порядке LIFO, последний зарезервированный блок всегда является следующим блоком, который должен быть освобожден. Это упрощает отслеживание стека, освобождение блока из стека - это не что иное, как настройка одного указателя. Память для переменных, выделенных в куче, выделяется во время выполнения, и доступ к этой памяти немного медленнее, но размер кучи ограничен только размером виртуальной памяти. Элементы кучи не зависят друг от друга и всегда могут быть доступны случайным образом в любое время. Вы можете выделить блок в любое время и освободить его в любое время. Это значительно усложняет отслеживание того, какие части кучи выделены или освобождены в любой момент времени. Вы можете использовать стек, если точно знаете, сколько данных вам нужно выделить до времени компиляции, и он не слишком велик. Вы можете использовать кучу, если не знаете точно, сколько данных вам понадобится во время выполнения, или если вам нужно выделить много данных. В многопоточной ситуации каждый поток будет иметь свой собственный полностью независимый стек, но они будут совместно использовать кучу. Стек зависит от потока, а куча зависит от приложения. Стек важно учитывать при обработке исключений и выполнении потоков. Каждый поток получает стек, в то время как обычно существует только одна куча для приложения (хотя нередко бывает несколько куч для разных типов распределения). Во время выполнения, если приложению требуется больше кучи, оно может выделить память из свободной памяти, а если стеку требуется память, оно может выделить память из свободной памяти, выделенной для приложения. Даже более подробно здесь и здесь. А теперь переходим к ответам на ваш вопрос. В какой степени они контролируются ОС или языковой средой? ОС выделяет стек для каждого потока системного уровня при создании потока. Обычно ОС вызывается средой выполнения языка для выделения кучи для приложения. Больше можно найти здесь. Каков их объем? Уже занесено в топ. «Вы можете использовать стек, если точно знаете, сколько данных вам нужно выделить до времени компиляции, и он не слишком большой. Вы можете использовать кучу, если не знаете точно, сколько данных вам понадобится во время выполнения или если вам нужно выделить много данных ". Больше можно найти здесь. От чего зависит размер каждого из них? Размер стека устанавливается ОС при создании потока. Размер кучи устанавливается при запуске приложения, но он может увеличиваться по мере необходимости в пространстве (распределитель запрашивает у операционной системы больше памяти). Что делает человека быстрее? Распределение стека происходит намного быстрее, поскольку все, что он действительно делает, это перемещает указатель стека. Используя пулы памяти, вы можете получить сопоставимую производительность из распределения кучи, но это связано с небольшой дополнительной сложностью и собственными головными болями. Кроме того, соотношение стека и кучи - это не только соображения производительности; он также многое говорит об ожидаемом времени жизни объектов. Подробности можно найти здесь. | ОК, просто и коротко, они означают заказанный, а не заказанный ...! Стек: в элементах стека вещи накладываются друг на друга, что означает, что их обработка будет быстрее и эффективнее! ... Таким образом, всегда есть указатель, указывающий на конкретный элемент, также обработка будет быстрее, между элементами также есть взаимосвязь! ... Куча: нет порядка, обработка будет медленнее, а значения перепутаны вместе без определенного порядка или индекса ... есть случайные и нет связи между ними ... поэтому время выполнения и использования может варьироваться ... Я также создаю изображение ниже, чтобы показать, как они могут выглядеть: | стек, куча и данные каждого процесса в виртуальной памяти: | В 1980-х годах UNIX распространилась, как кролики, с большими компаниями, открывшими свои собственные. У Exxon был один, как и у десятков торговых марок, утраченных историей. Расположение памяти оставалось на усмотрение многих разработчиков. Типичная программа на C была размещена в памяти с помощью возможность увеличения за счет изменения значения brk (). Обычно HEAP был чуть ниже этого значения brk. а увеличение brk увеличивало количество доступной кучи. Единственный СТЕК обычно представлял собой область ниже HEAP, которая была участком памяти. не содержит ничего ценного до вершины следующего фиксированного блока памяти. Следующим блоком часто был КОД, который мог быть перезаписан данными стека. в одном из самых известных хаков своего времени. Одним из типичных блоков памяти был BSS (блок нулевогоценности) что случайно не было обнулено ни в одном предложении производителя. Другой был DATA, содержащий инициализированные значения, включая строки и числа. Третьим был CODE, содержащий CRT (среда выполнения C), основные функции и библиотеки. Появление виртуальной памяти в UNIX меняет многие ограничения. Нет объективной причины, по которой эти блоки должны быть смежными, либо фиксированного размера, либо заказанного особым образом сейчас. Конечно, до UNIX была Multics, которая не страдала от этих ограничений. Вот схема, показывающая одну из схем памяти той эпохи. | Пара копеек: думаю, хорошо бы память рисовать графически и попроще: Стрелки - показывают, где растут стек и куча, размер стека процесса имеет ограничение, определенное в ОС, размер стека потока обычно ограничивается параметрами в API создания потока. Куча обычно ограничивается максимальным размером виртуальной памяти процесса, например, для 32 битов 2-4 ГБ. Очень простой способ: куча процессов является общей для процесса и всех потоков внутри, используется для распределения памяти в общем случае с чем-то вроде malloc (). Стек - это быстрая память для хранения в общем случае указателей возврата функций и переменных, обрабатываемых как параметры при вызове функции, локальных переменных функции. | Поскольку некоторые ответы были придирками, я собираюсь внести свою лепту. Удивительно, но никто не упомянул, что множественные (т.е. не связанные с количеством запущенных потоков уровня ОС) стеки вызовов можно найти не только в экзотических языках (PostScript) или платформах (Intel Itanium), но и в волокнах, зеленых потоках. и некоторые реализации сопрограмм. Волокна, зеленые нити и сопрограммы во многом похожи, что приводит к большой путанице. Разница между волокнами и зелеными потоками заключается в том, что первые используют кооперативную многозадачность, а вторые могут включать кооперативную или вытесняющую (или даже обе). Чтобы узнать о различиях между волокнами и сопрограммами, см. Здесь. В любом случае цель обоих волокон, зеленых потоков и сопрограмм состоит в том, чтобы несколько функций выполнялись одновременно, но не параллельно (см. Этот вопрос SO для различия) в одном потоке уровня ОС, передавая управление друг от друга назад и вперед организованно. При использовании волокон, зеленых потоков или сопрограмм у вас обычно есть отдельный стек для каждой функции. (Технически, не только стек, но и весь контекст выполнения для каждой функции. Самое главное, регистры ЦП.) Для каждого потока существует столько стеков, сколько одновременно выполняющихся функций, и поток переключается между выполнением каждой функции. согласно логике вашей программы. Когда функция работает до конца, ее стек уничтожается. Итак, количество и время жизни стеков являются динамическими и не определяются количеством потоков уровня ОС! Обратите внимание, что я сказал: «Обычно для каждой функции нужен отдельный стек». Существуют как стековые, так и бесстековые реализации курсовых программ. Наиболее заметными реализациями C ++ со стеком являются Boost.Coroutine и async / await Microsoft PPL. (Однако возобновляемые функции C ++ (также известные как «async и await»), которые были предложены для C ++ 17, скорее всего, будут использовать сопрограммы без стека.) Предложение волокон для стандартной библиотеки C ++ в ближайшее время. Также есть сторонние библиотеки. Зеленые потоки чрезвычайно популярны в таких языках, как Python и Ruby. | Мне есть чем поделиться, хотя основные моменты уже освещены. Стек Очень быстрый доступ. Хранится в оперативной памяти. Здесь загружаются вызовы функций вместе с переданными локальными переменными и параметрами функции. Когда программа выходит за пределы области видимости, пространство автоматически освобождается. Хранится в последовательной памяти. Куча Медленный доступ по сравнению со стеком. Хранится в ОЗУ. Здесь хранятся динамически создаваемые переменные, для чего позже потребуется освободить выделенную память после использования. Хранится везде, где выполняется выделение памяти, всегда доступен по указателю. Интересное примечание: Если бы вызовы функций были сохранены в куче, это привело бы к 2 беспорядочным точкам: Благодаря последовательному хранению в стеке выполнение происходит быстрее. Хранение в куче привело бы к огромным затратам времени, что замедлило бы выполнение всей программы. Если бы функции хранились в куче (беспорядочное хранилище, указанное указателем), не было бы возможности вернуться к адресу вызывающего абонента обратно (который дает стек из-за последовательного хранения в памяти). | Вот это да! Так много ответов, и я не думаю, что кто-то из них правильно понял ... 1) Где и что они (физически в памяти реального компьютера)? Стек - это память, которая начинается с наивысшего адреса памяти, выделенного для образа вашей программы, а затем оттуда значение уменьшается. Он зарезервирован для параметров вызываемой функции и для всех временных переменных, используемых в функциях. Есть две кучи: публичная и приватная. Частная куча начинается на 16-байтовой границе (для 64-разрядных программ) или 8-байтовой границе (для 32-разрядных программ) после последнего байта кода в вашей программе, а затем увеличиваетсязначение оттуда. Ее также называют кучей по умолчанию. Если частная куча станет слишком большой, она будет перекрывать область стека, как и стек, если он станет слишком большим. Поскольку стек начинается с более высокого адреса и спускается к более низкому адресу, при правильном взломе вы можете сделать стек настолько большим, что он будет выходить за пределы частной области кучи и перекрывать область кода. Уловка состоит в том, чтобы перекрыть достаточно области кода, чтобы вы могли вставить его в код. Это немного сложно сделать, и вы рискуете привести к сбою программы, но это легко и очень эффективно. Общедоступная куча находится в собственном пространстве памяти за пределами пространства образа вашей программы. Именно эта память будет перекачана на жесткий диск, если ресурсы памяти станут недостаточными. 2) В какой степени они контролируются ОС или языковой средой? Стек контролируется программистом, частная куча управляется ОС, а общедоступная куча никем не контролируется, потому что это служба ОС - вы делаете запросы, и они либо предоставляются, либо отклоняются. 2b) Каков их объем? Все они глобальны для программы, но их содержимое может быть частным, общедоступным или глобальным. 2в) От чего зависит размер каждого из них? Размер стека и частной кучи определяется параметрами среды выполнения вашего компилятора. Общедоступная куча инициализируется во время выполнения с помощью параметра размера. 2г) Что делает человека быстрее? Они не созданы для того, чтобы быть быстрыми, они созданы для того, чтобы быть полезными. От того, как программист их использует, зависит, будут они «быстрыми» или «медленными». ССЫЛКА: https://norasandler.com/2019/02/18/Write-a-Compiler-10.html https://docs.microsoft.com/en-us/windows/desktop/api/heapapi/nf-heapi-getprocessheap https://docs.microsoft.com/en-us/windows/desktop/api/heapapi/nf-heapi-heapcreate | Многие ответы правильны как концепции, но мы должны отметить, что стек необходим для оборудования (например, микропроцессора), чтобы разрешить вызов подпрограмм (CALL на языке ассемблера ...). (Ребята из ООП назовут это методами) В стеке вы сохраняете адреса возврата, а call → push / ret → pop управляется непосредственно аппаратно. Вы можете использовать стек для передачи параметров ... даже если он медленнее, чем использование регистров (скажет ли гуру микропроцессоров или хорошая книга BIOS 1980-х ...) Без стека не может работать ни один микропроцессор. (мы не можем представить программу даже на ассемблере без подпрограмм / функций) Без кучи может. (Программа на ассемблере может работать без, поскольку куча - это концепция ОС, а также без malloc, то есть вызова OS / Lib. Использование стека происходит быстрее: Есть аппаратное обеспечение, и даже push / pop очень эффективны. malloc требует входа в режим ядра, использования блокировок / семафоров (или других примитивов синхронизации), выполнения некоторого кода и управления некоторыми структурами, необходимыми для отслеживания распределения. | Куча - это область динамически выделяемой памяти, которой автоматически управляет операционная система или библиотека диспетчера памяти. Вы можете выделить блок в любое время и освободить его в любое время. Выделение кучи требует ведения полной записи о том, какая память выделена, а что нет, а также некоторых накладных расходов для уменьшения фрагментации, поиска смежных сегментов памяти, достаточно больших, чтобы соответствовать запрошенному размеру, и т. Память можно освободить в любой момент, оставив свободное место. По мере роста кучи новые блоки часто распределяются с более низких адресов на более высокие. Таким образом, вы можете думать о куче как о куче блоков памяти, размер которой увеличивается по мере выделения памяти. Если куча слишком мала для выделения, размер часто можно увеличить, получив больше памяти из базовой операционной системы. Память, выделенная из кучи, будет оставаться выделенной до тех пор, пока не произойдет одно из следующих событий: Память освобождена Программа завершается Стек: Хранится в оперативной памяти компьютера как в куче. Переменные, созданные в стеке, выходят из области видимости и автоматически освобождаются. Гораздо быстрее выделять по сравнению с переменными в куче. Хранит локальные данные, адреса возврата, используемые для передачи параметров. Может иметь место переполнение стека, когда используется слишком много стека (в основном от бесконечной или слишком глубокой рекурсии, очень большие выделения). Вы бы использовали стек, если точно знаете, сколько данных вам нужно выделить до времени компиляции, и он не слишком большой. Обычно максимальный размер уже определен, когда ваша программа начинается. Куча: Хранится в оперативной памяти компьютера как в стеке. В C ++ переменные в куче должны быть уничтожены вручную и никогда выпадают из сферы действия. Данные освобождаются с помощью delete, delete [] или free. Медленнее выделяется по сравнению с переменными в стеке. Используется по запросу для выделения блока данных для использования программой. Может иметь место фрагментация при большом количестве распределений и освобождение. В C ++ или C данные, созданные в куче, будут указываться указателями и выделяются new или malloc соответственно. Могут происходить сбои выделения, если запрашивается слишком большой буфер. быть выделенным. Выбудет использовать кучу, если вы не знаете точно, сколько данных вы потребуется во время выполнения или если вам нужно выделить много данных. Ответственный за утечки памяти. | Стек - это, по сути, легкодоступная память, которая просто управляет своими элементами. как - ну - стек. В стопку могут попасть только предметы, размер которых известен заранее. Это относится к числам, строкам и логическим значениям. Куча - это память для элементов, для которых вы не можете заранее определить точный размер и структура. Поскольку объекты и массивы можно изменять и изменяются во время выполнения, они должны уходить в кучу. Источник: Academind | Стек и куча ЦП физически связаны с тем, как ЦП и регистры работают с памятью, как работает язык машинного ассемблера, а не сами языки высокого уровня, даже если эти языки могут решать мелочи. Все современные процессоры работают с «одной и той же» теорией микропроцессоров: все они основаны на так называемых «регистрах», а некоторые предназначены для «стека» для повышения производительности. У всех процессоров с самого начала есть стековые регистры, и, как я знаю, они всегда были здесь, так сказать. Языки ассемблера одинаковы с самого начала, несмотря на различия ... вплоть до Microsoft и его промежуточного языка (IL), который изменил парадигму, чтобы иметь язык ассемблера виртуальных машин OO. Так что в будущем мы сможем иметь некоторый процессор CLI / CIL (один проект MS). ЦП имеют регистры стека для ускорения доступа к памяти, но они ограничены по сравнению с использованием других регистров для получения полного доступа ко всей доступной памяти для процесса. Вот почему мы говорили о выделении стека и кучи. Таким образом, куча является большой и медленной и предназначена для «глобальных» экземпляров и содержимого объектов, поскольку стек небольшой и быстрый, а также для «локальных» переменных и ссылок (скрытые указатели, чтобы забыть управлять ими). Итак, когда мы используем ключевое слово new в методе, ссылка (int) создается в стеке, но объект и все его содержимое (типы значений, а также объекты) создаются в куче, если я помню. Но в стеке создаются локальные элементарные типы значений и массивы. Разница в доступе к памяти заключается на уровне ссылок на ячейки: адресация кучи, общей памяти процесса, требует большей сложности с точки зрения обработки регистров ЦП, чем стек, который «более» локально с точки зрения адресации, потому что стек ЦП регистр используется как базовый адрес, если я помню. Вот почему, когда у нас очень длинные или бесконечные рекурсивные вызовы или циклы, у нас происходит быстрое переполнение стека, без зависания системы на современных компьютерах ... C # Heap (ing) против стека (ing) в .NET Стек против кучи: узнайте разницу Выделение памяти статическим классом, где она хранится C # Что и где стопка и куча? https://en.wikipedia.org/wiki/Memory_management https://en.wikipedia.org/wiki/Stack_register Ресурсы на ассемблере: Учебник по программированию сборки Руководства для разработчиков ПО для архитектур Intel® 64 и IA-32 | Спасибо за действительно хорошее обсуждение, но как настоящий новичок мне интересно, где хранятся инструкции? В НАЧАЛЕ ученые выбирали между двумя архитектурами (фон NEUMANN, где все считается ДАННЫМИ, и HARVARD, где область памяти была зарезервирована для инструкций, а другая - для данных). В конечном итоге мы остановились на дизайне фон Неймана, и теперь все считается «одинаковым». Мне было трудно, когда я учился сборке https://www.cs.virginia.edu/~evans/cs216/guides/x86.html потому что они говорят о регистрах и указателях стека. Все выше говорит о ДАННЫХ. Я предполагаю, что, поскольку инструкция - это определенная вещь с определенным объемом памяти, она будет помещена в стек, и поэтому все «эти» регистры, обсуждаемые в сборке, находятся в стеке. Конечно, затем пришло объектно-ориентированное программирование с инструкциями и данными, объединенными в структуру, которая была динамической, так что теперь инструкции также будут храниться в куче? | Весьма активный вопрос. Заработайте 10 репутации, чтобы ответить на этот вопрос. Требование репутации помогает защитить этот вопрос от спама и отсутствия ответов. Не тот ответ, который вы ищете? Просмотрите другие вопросы с метками memory-management stack, language-agnostic heap, dynamic-memory-allocation, или задайте свой вопрос.